package com.sunlands.deskmate.channel.schedule;

import com.sunlands.deskmate.constant.YN;
import com.sunlands.deskmate.channel.ChannelInfo;
import com.sunlands.deskmate.channel.ChannelManager;
import io.netty.channel.Channel;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RMapCache;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import java.util.Objects;
import java.util.concurrent.TimeUnit;

import static com.sunlands.deskmate.channel.ChannelManager.*;

/**
 * redis channel与local channel 数据一致性以及有效性检查，及时剔除无效channel
 */
@EnableScheduling
@Service
@Slf4j
public class TaskCheckChannel {

    @Value("${eureka.debug:false}")
    private Boolean debug;

    /**
     * 检查本地通道仓库和远程仓库数据一致性，强行一致，否则释放通道
     * 此方法还有redisChannelStore的保活作用，远程仓库中的通道活跃时间为 REDIS_CHANNEL_MAX_IDLE_TIME
     */
    @Scheduled(cron = "${scheduled.checkChannel}")
    public void checkChannel() {

        RMapCache<String, ChannelInfo> channelRedisSet = getRedisChannelStore();
        ChannelManager.getAllChannel().forEach((key, value) -> {
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            ChannelInfo redisChannelInfo = channelRedisSet.get(key);
            ChannelInfo channelInfo = value.attr(CHANNEL_INFO).get();
            if (Objects.isNull(redisChannelInfo)) {
                log.info("定时检查通道 通道异常 - 远程通道为空 channelInfo = {}", channelInfo);

                if (Objects.nonNull(channelRedisSet.putIfAbsent(key, channelInfo, REDIS_CHANNEL_TIME_OUT, TimeUnit.DAYS, REDIS_CHANNEL_MAX_IDLE_TIME, TimeUnit.MINUTES))) {
                    value.close();
                    log.error("定时检查通道，添加通道失败，移除通道 channelInfo = {}", channelInfo);
                }

            } else {

                if (redisChannelInfo.getCreateTime() > channelInfo.getCreateTime()) {
                    value.close();
                    log.info("定时检查通道，检查redis channel创建早于本地channel，移除通道 channelInfo = {}", channelInfo);

                } else if (redisChannelInfo.getCreateTime() < channelInfo.getCreateTime()) {
                    boolean remove = channelRedisSet.remove(key, redisChannelInfo);
                    ChannelInfo ifAbsent = channelRedisSet.putIfAbsent(key, channelInfo, REDIS_CHANNEL_TIME_OUT, TimeUnit.DAYS, REDIS_CHANNEL_MAX_IDLE_TIME, TimeUnit.MINUTES);

                    if (!(remove && Objects.isNull(ifAbsent))) {
                        log.info("定时检查通道，检查redis channel创建晚于本地channel，替换通道 channelInfo = {}", channelInfo);
                    } else {
                        log.error("定时检查通道，检查redis channel创建晚于本地channel，替换通道失败 channelInfo = {}", channelInfo);
                    }
                }

            }
        });
    }

    /**
     * 检查通道心跳是否正常，失效的通道进行关闭
     */
    @Scheduled(cron = "${scheduled.checkChannelHeart}")
    public void checkChannelHeart() {
        if (debug) {
            log.warn("定时检查通道-本地环境不启动定时");
            return;
        }

        ChannelManager.getAllChannel().keySet().forEach(key -> {
            Channel channel = getChannel(key);
            Long heartTime =  ChannelManager.getHeartTime(channel);
            Integer topKey =  ChannelManager.getTopKey(channel);
            long time = (System.currentTimeMillis() - heartTime) / 1000;
            ChannelInfo channelInfo = channel.attr(CHANNEL_INFO).get();
            //超过3次没有心跳且程序不在后台运行，关闭该用户通道
            if (time > HEART_INTERVAL * 3 && YN.Y.code.equals(topKey)) {
                log.info("心跳超时 释放通道 超时时间 time = {} channelInfo = {}", time, channelInfo);
                channel.close();
            }
        });
    }

}